package com.ruoyi.web.controller.common.query;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.lang.reflect.Field;
import java.util.Map;

/**
 * 查询参数构造器
 *
 * @author 王涛
 * @version 1.0
 * @createTime 2021-03-01 09:47:34
 */
public class Querys {
    /**
     * 升序
     */
    public static final String ASC = "asc";

    /**
     * 获取分页对象
     *
     * @param pageModel 分页信息
     * @return 分页对象
     */
    public static <T> Page<T> page(PageModel pageModel) {
        //当前页
        Integer pageNo = pageModel.getPageNo();
        //如为空 默认1
        pageNo = pageNo == null ? 1 : pageNo;
        //页面大小
        Integer pageSize = pageModel.getPageSize();
        //如为空 默认20
        pageSize = pageSize == null ? 20 : pageSize;
        //排序字段 防止SQL注入（因为sidx、order是通过拼接SQL实现排序的，会有SQL注入风险）
        String sortField = sqlInject(pageModel.getSortField());
        //排序方式
        String sortWay = pageModel.getSortWay();

        //分页对象
        Page<T> page = new Page<>(pageNo, pageSize);


        //前端字段排序
        if (StrUtil.isNotEmpty(sortField) && StrUtil.isNotEmpty(sortWay)) {
            sortField = StrUtil.toSymbolCase(sortField, '_');

            if (ASC.equalsIgnoreCase(sortWay)) {
                page.addOrder(OrderItem.asc(sortField));
            } else {
                page.addOrder(OrderItem.desc(sortField));
            }
        }

        return page;
    }


    /**
     * SQL注入过滤
     *
     * @param str 待验证的字符串
     */
    public static String sqlInject(String str) {
        if (StrUtil.isBlank(str)) {
            return null;
        }
        //去掉'|"|;|\字符
        str = StrUtil.replace(str, "'", "");
        str = StrUtil.replace(str, "\"", "");
        str = StrUtil.replace(str, ";", "");
        str = StrUtil.replace(str, "\\", "");

        //转换成小写
        String str1 = str.toLowerCase();

        //非法字符
        String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};

        //判断是否包含非法字符
        for (String keyword : keywords) {
            if (str1.contains(keyword)) {
                throw new RuntimeException("包含非法字符");
            }
        }

        return str;
    }

    /**
     * 获取条件构造器
     * 如需自定义需要删除字段上的注解然后手动构建条件
     * 获取参数对象中字段值不为空的自动封装条件  默认为EQ(=)
     *
     * @param param 查询参数
     * @return 查询条件
     */
    public static <T> QueryWrapper<T> wrapper(Object param) {
        //条件构造器
        QueryWrapper<T> wrapper = Wrappers.query();
        if (param != null) {
            //获取对象的类对象
            Class<?> clazz = param.getClass();
            //将对象转为map
            Map<String, Object> map = BeanUtil.beanToMap(param);
            map.forEach((key, val) -> {
                if (val != null && StrUtil.isNotBlank(val.toString())) {
                    try {
                        //获取字段
                        Field field = clazz.getDeclaredField(key);
                        //获取字段上的注解
                        QueryField annotation = field.getAnnotation(QueryField.class);
                        //获取条件
                        if (annotation != null) {
                            Comparison comparison = annotation.comparison();
                            //表列名 默认为驼峰转下划线
                            String column = StrUtil.toSymbolCase(key, '_');
                            switch (comparison) {
                                case EQ:
                                    wrapper.eq(column, val);
                                    break;
                                case GT:
                                    wrapper.gt(column, val);
                                    break;
                                case GE:
                                    wrapper.ge(column, val);
                                    break;
                                case LT:
                                    wrapper.lt(column, val);
                                    break;
                                case LE:
                                    wrapper.le(column, val);
                                    break;
                                case NE:
                                    wrapper.ne(column, val);
                                    break;
                                case LIKE:
                                    wrapper.like(column, val);
                                    break;
                                default:
                            }
                        }
                    } catch (NoSuchFieldException e) {
                        throw new RuntimeException("未获取到字段属性");
                    }
                }
            });
        }
        return wrapper;
    }
}
